package com.ygl.core.listener.loadbalance;

import com.netflix.loadbalancer.Server;
import com.ygl.core.adapter.EnvironmentRouteAdapter;
import com.ygl.core.listener.BasicListener;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.Iterator;
import java.util.List;

/**
 * @Author yanggld
 * @Date 2019/12/18-17:18
 * @Description
 */
@Slf4j
public class EnvironmentFilterLoadBalanceListener extends BasicListener implements LoadBalanceListener{

	@Autowired(required = false)
	private EnvironmentRouteAdapter environmentRouteAdapter;

	@Override
	public void onGetServers(String serviceId, List<? extends Server> servers) {
		applyEnvironmentFilter(serviceId, servers);
		if (servers != null) {
			String consumerServiceId = coreAdapter.getServiceId();
			String consumerServiceEnvironment = coreAdapter.getEnvironment();
			log.info(consumerServiceId+":"+consumerServiceEnvironment+"------>>>>>>"+serviceId+"--------环境隔离匹配结果："+servers.size());
		}
	}

	private void applyEnvironmentFilter(String providerServiceId, List<? extends Server> servers) {
		String environment = coreAdapter.getEnvironment();
		boolean noEnvironmentRoute = noEnvironmentRoute(servers, environment);
		Iterator<? extends Server> iterator = servers.iterator();
		while (iterator.hasNext()) {
			Server server = iterator.next();
			String serverEnvironment = coreAdapter.getServerEnvironment(server);
			// 如果不需要跨环境路由，本环境内可完成服务调用
			if (noEnvironmentRoute) {
				// 环境隔离：调用端实例和提供端实例的元数据Metadata环境配置值相等才能调用
				if (!StringUtils.equals(serverEnvironment, environment)) {
					iterator.remove();
				}
			} else {
				// 环境路由：环境隔离下，调用端实例找不到符合条件的提供端实例，把流量路由到一个通用或者备份环境，例如：元数据Metadata环境配置值为common（该值可配置，但不允许为保留值default）
				if (environmentRouteAdapter != null && environmentRouteAdapter.isRouteEnabled()) {
					if (!StringUtils.equals(serverEnvironment, environmentRouteAdapter.getEnvironmentRoute())) {
						iterator.remove();
					}
				} else {
					// 环境路由未开启，移除所有不匹配的实例
					iterator.remove();
				}
			}
		}
	}

	/**
	 * 优先本环境之间服务调用，如果无法本环境之间调用，就要准备跨环境调用。
	 * 判断环境是否要路由。只要调用端实例和至少一个提供端实例的元数据Metadata环境配置值相等，就不需要路由
	 * @param servers
	 * @param environment
	 * @return true：不需要路由； false： 需要路由
	 */
	private boolean noEnvironmentRoute(List<? extends Server> servers, String environment) {
		for (Server server : servers) {
			String serverEnvironment = coreAdapter.getServerEnvironment(server);
			if (StringUtils.equals(serverEnvironment, environment)) {
				return true;
			}
		}
		return false;
	}
}
